/* Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
  <file> uls_lex.h </file>
  <brief>
    Implements the main routines of ULS, such as uls_create(), 
      uls_gettok(), uls_destroy(), ...
    This file is part of ULS, Unified Lexical Scheme.
  </brief>
  <author>
    Stanley J. Hong <babel96@gmail.com>, April 2011.
  </author>
*/

#ifndef __ULS_LEX_H__
#define __ULS_LEX_H__

#include "uls_const.h"
#include "uls_conf.h"
#include "uls_istream.h"
#include "istr_fd.h"
#include "uls_lf_sprintf.h"
#ifndef WIN32
#include "fdfilter.h"
#endif

#ifdef __cplusplus
extern "C" {
#endif

#define ULS_LOG_EMERG     0
#define ULS_LOG_ALERT     1
#define ULS_LOG_CRIT      2
#define ULS_LOG_ERROR     3
#define ULS_LOG_WARN      4
#define ULS_LOG_NOTICE    5
#define ULS_LOG_INFO      6
#define ULS_LOG_DEBUG     7
#define ULS_LOG_N_SYSTEMS 8

#define ULS_MAX_LOGLEVEL  (sizeof(uls_uint32)*8 - 1)
#define ULS_LOGLEVEL_FLAG(lvl)  (1<<(lvl))

#define ULS_CASE_INSENSITIVE   0x0001
#define ULS_WANT_LF_CHAR       0x0002
#define ULS_WANT_TAB_CHAR      0x0004

struct _uls_lex {
	uls_version_t config_filever;
	uls_version_t stream_filever;
	uls_flags_t flags;

	int           tok;
	uls_char_t    *s_val;
	int           s_val_len;

	uls_char_t    *tokbuf;
	int           tokbuf_siz;
	int           n_digits, expo;

	uls_istream_t i_str;

	/*
	 * str_pool = lxm_array + lxm_tokid_sorted + lxm_intrinsic,...
	 */
	char spec_name[ULS_LEXSTR_MAXSIZ+1];
	uls_version_t spec_ver;

	uls_strcmp_t lxm_strcmp;
	uls_tokdef_t **lxm_array;
	int n_lxm_array, siz_lxm_array;

	uls_tokdef_t **lxm_tokid_sorted;
	int n_lxm_tokid_sorted;

	uls_tokdef_t **lxm_intrinsic;
	int n_lxm_intrinsic;

	uls_tokdef_t *lxm_1char;
	uls_kwtable_t   lxm_keyw_table;
	istr_context_t *istr_tower;

	int toknum_EOI, toknum_EOF, toknum_ERR, toknum_NONE;
	int toknum_ID, toknum_NUMBER, toknum_LINENUM;

	unsigned int idfirst_charset_1[ULS_N_CHARSET_RANGES];
	unsigned int idfirst_charset_2[ULS_N_CHARSET_RANGES];
	int n_idfirst_charsets;

	unsigned int id_charset_1[ULS_N_CHARSET_RANGES];
	unsigned int id_charset_2[ULS_N_CHARSET_RANGES];
	int n_id_charsets;

	char icnst_suffixes[ULS_CNST_SUFFIXES_MAXSIZ+1];
	char fcnst_suffixes[ULS_CNST_SUFFIXES_MAXSIZ+1];

	void          *syslog;
	uls_uint32    loglevel;
	uls_lf_puts_t syslog_puts;
	uls_lf_csz_t mb_lbuf;
};

#define ULS_STREAM_WRITING     0x01
#define ULS_STREAM_FDCLOSE     0x02
#define ULS_FL_LINE_NUMBERING  0x10

struct _uls_stream {
	int        flags;

	uls_version_t filever;
	char       specname[ULS_LEXSTR_MAXSIZ+1];
	char       tag[ULS_FILEPATH_MAX+1];
	int        filetype;
	char       subname[ULS_STREAM_SUBNAME_SIZE+1];
	char       ctime[ULS_STREAM_CTIME_SIZE+1];

	int        fd;
	uls_char_t firstline[ULS_MAGICCODE_SIZE+1];
	int        len_firstline;

	uls_lex_t  *uls;

	int out_fd;
	int out_fd_mode;
	uls_char_t *outbuf;
	int  outbuf_siz;

};

#define uls_tok_id(uls) ((uls)->tok)
#define uls_token_id(uls) ((uls)->tok)
#define uls_lexeme(uls) ((uls)->s_val)
#define uls_lexeme_len(uls) ((uls)->s_val_len)
#define uls_lexeme_text(uls) ((uls)->s_val)
#define uls_lexeme_textlen(uls) ((uls)->s_val_len)

// You may call this when you receive TOK_EOF.
#define uls_current_fd(uls) ((uls)->i_str.fd_context.fd_source.fd)
#define uls_is_eoi(uls) ((uls)->tok == (uls)->toknum_EOI)
#define uls_is_eof(uls) ((uls)->tok == (uls)->toknum_EOF)
#define uls_is_err(uls) ((uls)->tok == (uls)->toknum_ERR)
#define uls_is_id(uls) ((uls)->tok == (uls)->toknum_ID)
#define uls_is_number(uls) ((uls)->tok == (uls)->toknum_NUMBER)

#define uls_set_tag(uls,tagstr) uls_istr_set_tag(&(uls)->i_str, tagstr, -1)
#define uls_set_lineno(uls,lno) uls_istr_set_tag(&(uls)->i_str, NULL, lno)
#define uls_inc_lineno(uls,n_delta) uls_istr_inc_lineno(&(uls)->i_str, n_delta)

#define uls_get_lineno(uls) ((uls)->i_str.fd_context.lineno)
#define uls_get_tag(uls) ((const char *) (uls)->i_str.fd_context.tag)

#define uls_n_buckets_kwtable(uls) ((uls)->lxm_keyw_table.n_buckets)

void uls_set_loglevel(uls_lex_t* uls, int lvl);
int  uls_loglevel_isset(uls_lex_t* uls, int lvl);
void uls_clear_loglevel(uls_lex_t* uls, int lvl);

uls_lex_t* uls_create(const char* confname);
int   uls_init(uls_lex_t* uls, const char* confname);
void  uls_deinit(uls_lex_t* uls);
void  uls_destroy(uls_lex_t* uls);

void uls_change_strcmp(uls_lex_t* uls, uls_strcmp_t proc);

#define uls_delete_lit_analyzer(uls,pfx) istr_delete_lit_analyzer(&(uls)->i_str,pfx)
#define uls_change_lit_analyzer(uls,pfx,proc) istr_change_lit_analyzer(&(uls)->i_str,pfx,proc)

int uls_set_fd_type(uls_lex_t* uls, int fd, int fd_type, const char* tag, int flags);
int uls_push_fd_type(uls_lex_t* uls, int fd, int fd_type, const char* tag, int flags);
int uls_push_fd_type_hdr(uls_lex_t* uls, uls_stream_t* hdr, int flags);
#define uls_push_fd(uls,fd, flags) uls_push_fd_type(uls, fd, ULS_STREAM_RAW, "?", flags)
#define uls_set_fd(uls, fd, flags) uls_set_fd_type(uls, fd, ULS_STREAM_RAW, "?", flags)

int uls_push_file_hdr(uls_lex_t* uls, uls_stream_t* hdr, int flags);
int uls_push_file(uls_lex_t* uls, const char* filepath, int flags);
int uls_set_file_hdr(uls_lex_t* uls, uls_stream_t* hdr, int flags);
int uls_set_file(uls_lex_t* uls, const char* filepath, int flags);

void  uls_push_line(uls_lex_t* uls, char* line, int len, int flags);
void  uls_set_line(uls_lex_t* uls, char* line, int len, int flags);

uls_char_t* uls_skip_white_spaces(uls_lex_t* uls);
uls_char_t  uls_peekch_detail(uls_lex_t* uls, istr_quotetype_t** pp_quotetype);
#define uls_peekch(uls) uls_peekch_detail(uls, NULL)
uls_char_t uls_getch(uls_lex_t* uls);
#define ULS_NEXTCH_NONE  0
#define ULS_NEXTCH_QUOTE 1
int uls_ungetch(uls_lex_t* uls);

int  uls_gettok(uls_lex_t* uls);
void uls_settok(uls_lex_t* uls, int tokid, char* lexeme, int l_lexeme);
void uls_pushback(uls_lex_t* uls, int sym_no, void* dat, int dat_len);
#define uls_ungettok(uls) uls_pushback(uls, (uls)->tok, (void *) ((uls)->s_val), (uls)->s_val_len)
void uls_expect(uls_lex_t* uls, int value);
void  uls_prntok(uls_lex_t* uls);

int uls_is_integer(uls_lex_t* uls);
int uls_is_real(uls_lex_t* uls);

unsigned long uls_lexeme_ulong(uls_lex_t* uls);
int uls_lexeme_int(uls_lex_t* uls);
double uls_lexeme_double(uls_lex_t* uls);

int uls_create_stream(uls_stream_t *hdr, uls_lex_t* uls, int fd, int mode, char* subname);
int uls_open_stream_file(const char* filepath, uls_stream_t* hdr);
int uls_start_stream(uls_stream_t *hdr, uls_stream_t* in_hdr, int flags);
int uls_close_stream(uls_stream_t *hdr);
#ifndef WIN32
int uls_open_stream_filter_fd(int fd, fdf_t* fdf, uls_stream_t* hdr);
void uls_close_stream_filter(uls_stream_t *hdr, fdf_t* fdf);
#endif
void uls_init_stream(uls_stream_t *hdr, uls_lex_t* uls, int fd);
void uls_deinit_stream(uls_stream_t *hdr);
int uls_open_stream_fd(int fd, uls_stream_t *hdr);

uls_char_t* uls_get_keyword(uls_lex_t* uls, int t);

#ifdef __cplusplus
}
#endif

#endif 
